package com.snapp.util;

import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

import org.jdom.Element;
import org.jdom.JDOMException;

import com.snapp.util.object.model.ObjectModel;
import com.snapp.util.object.model.ObjectImpl;

public class Bean implements Serializable {
	private static final long serialVersionUID = 1183051928650990881L;
	
	private String name = "bean";
	private Vector<String> propertyNames = null;
	private Vector<Object> properties = null;
	private Vector<String> propertyStrings = null;
	
	public Bean() {
		propertyNames = new Vector<String>();
		properties = new Vector<Object>();
		propertyStrings = new Vector<String>();
	}
	
	@SuppressWarnings("unchecked")
	public Bean getCopy() {
		Bean bean = new Bean();
		bean.setName(this.name);
		bean.setPropertyNames((Vector<String>)propertyNames.clone());
		bean.setProperties((Vector<Object>)properties.clone());
		bean.setPropertyStrings((Vector<String>)propertyStrings.clone());
		return bean;
	}
	
	public void populate(Map<String, Object> props) {
		Iterator<String> itr = props.keySet().iterator();
		while(itr.hasNext()) {
			String key = itr.next();
			setProperty(key, props.get(key), props.get(key).toString());
		}
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	private int addPropertyName(String nm) {
		if (!this.propertyNames.contains(nm)) this.propertyNames.add(nm);
		return this.propertyNames.indexOf(nm);
	}
	
	public Vector<String> getPropertyNames() {
		return this.propertyNames;
	}

	public void setPropertyNames(Vector<String> propertyNames) {
		this.propertyNames = propertyNames;
	}

	public void setProperty(String nm, Object prop, String stringVal) {
		int ndx = addPropertyName(nm);
		if (ndx >= this.properties.size()) {
			this.properties.add(prop);
		} else {
			this.properties.setElementAt(prop,ndx);
		}
		if (ndx >= this.propertyStrings.size()) {
			this.propertyStrings.add(stringVal);  
		} else {
			this.propertyStrings.setElementAt(stringVal,ndx);  
		}
	}
	
	public Object getProperty(String nm) {
		return propertyNames.contains(nm) ? properties.get(propertyNames.indexOf(nm)) : null; 
	}
	
	public void removeProperty(String nm) {
		this.properties.remove(this.propertyNames.indexOf(nm));
		this.propertyStrings.remove(this.propertyNames.indexOf(nm));
		this.propertyNames.remove(nm);
	}
	
	public Vector<Object> getProperties() {
		return this.properties;
	}
	
	public void setProperties(Vector<Object> props) {
		this.properties = props;
	}
	
	public boolean contains(String propname) {
		return propertyNames.contains(propname);
	}
	/**
	 * 
	 */
	public String getPropertyString(String nm) {
		return propertyNames.contains(nm) ? propertyStrings.get(propertyNames.indexOf(nm)) : null;
	}

	public Vector<String> getPropertyStrings() {
		return propertyStrings;
	}

	public void setPropertyStrings(Vector<String> propertyStrings) {
		this.propertyStrings = propertyStrings;
	}
	
	public Element toXML() throws JDOMException {
		Element el = new Element(name);
		Iterator<String> i = propertyNames.iterator();
		while(i.hasNext()) {
			String nm = i.next();
			int ndx = propertyNames.indexOf(nm);
			// get value... or empty string if null (xml friendly)
			String val = propertyStrings.get(ndx) == null ? "": propertyStrings.get(ndx);
			// set the attribute
			el.setAttribute(nm, val);
			
			// check for children to recursively build xml structure
			if (properties.get(ndx).getClass().equals(ObjectImpl.class)) {
				el.addContent(((ObjectImpl)properties.get(ndx)).getBean().toXML());
				el.removeAttribute(nm);
			} else if (properties.get(ndx).getClass().equals(Bean.class)) {
				el.addContent(((Bean)properties.get(ndx)).toXML());
				el.removeAttribute(nm);
			} else if (properties.get(ndx).getClass().equals(new Vector<ObjectModel>().getClass())) {
				try {
					@SuppressWarnings("unchecked")
					Vector<ObjectModel> v = (Vector<ObjectModel>)properties.get(ndx);
					el.addContent(ObjectImpl.listToXML(v).setName(val));
					el.removeAttribute(nm);
				} catch(Exception e) {}
			}
		}
		return el;
	}
	
}
